package ie.dit.reg08.attSelector;

import ie.dit.reg08.manager.AttributeSet;
import ie.dit.reg08.manager.Entity;
import ie.dit.reg08.manager.Trial;
import ie.dit.reg08.manager.greInterface;

import java.util.Enumeration;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.Set;
import java.util.TreeMap;
import java.util.Vector;

public class Selector {

	
	/*
	 * Keys = Frequency of attribute used
	 */
	//TreeMap tmAttFreq;
	/*
	 * Keys = Attribute, Values = Frequencies
	 */
	HashMap<String, Integer> hmAttFreq;
	int totalCount;
	Vector<Trial> vTrials;

	
	public Selector(Vector<Trial> v) {

		vTrials = (Vector<Trial>) v.clone();		
		//Comparator < Integer > reverse = Collections.reverseOrder();
		//tmAttFreq = new TreeMap(reverse);
		totalCount = 0;
		
		computeAttFreq(true);
		outputDimensionalUsageAnalysis();
		//outputCorpusData();
		//corpusAnomalies();
		//outputNondistinguishingTrials();
		

		//corpusSystemDifferences();
	}
	
	/*
	 * This function returns a Vector of objects that implement the greInterface interfact.
	 * Each object in the vector contains the attribute set for one of the trials in the
	 * training corpus
	 */
	public Vector<greInterface> selectAttributes() {
		//-------------------------------------------------------------------
		//create descriptions
		//-------------------------------------------------------------------
		Vector<greInterface> vSysDescriptions = new Vector<greInterface>();		
		boolean includetype = true;
		boolean enforcedistractorsexcluded = true;
		Iterator<Trial> i = vTrials.iterator();
		while(i.hasNext()) {
			vSysDescriptions.add(new Incremental1(i.next(), hmAttFreq, totalCount, includetype, enforcedistractorsexcluded));
		}		
		return vSysDescriptions;
	}
	
	
	/*
	 * This function iterates over the vTrials vector and outputs the id's of the trials
	 * whose corpus description is <b>not distinguishing</b> or whose corpus description contains
	 * an <b>other</b> component.
	 */
	public void corpusAnomalies() {
		Iterator<Trial> j = vTrials.iterator();
		Trial t;
		while(j.hasNext()) {
			t = j.next();
			if(!t.IsDistinguishing()) {
				System.out.println("Trial " + t.getID() + ": corpus description is not distinguishing!");
			}
			if(t.otherAttribute()) {
				System.out.println("Trial " + t.getID() + ": corpus description contains undefined other attribute!");
			}
		}

	}
	
	
	/*
	 * For each trial in the corpus output each attribute in the trial corpus description that
	 * is not included in the system's attribute-set and each attribute in the system's attribute-set
	 * that is not in the trial's description.
	 */
	public void corpusSystemDifferences(Vector<greInterface> vSysAttSet) {
		
		Iterator<Trial> iterT;
		Iterator <greInterface> iterD;
		Trial tmpT;
		Hashtable<String, String> htDes, htGRE;
		
		Hashtable<String, Integer> htMissing;
		Hashtable<String, Integer> htExtra;
		htMissing = new Hashtable<String, Integer>();
		htMissing.put(new String("orientation"), new Integer(0));
		htMissing.put(new String("colour"), new Integer(0));
		htMissing.put(new String("type"), new Integer(0));
		htMissing.put(new String("x-dimension"), new Integer(0));
		htMissing.put(new String("y-dimension"), new Integer(0));
		htMissing.put(new String("other"), new Integer(0));
		htExtra = new Hashtable<String, Integer>();
		htExtra.put(new String("orientation"), new Integer(0));
		htExtra.put(new String("colour"), new Integer(0));
		htExtra.put(new String("type"), new Integer(0));
		htExtra.put(new String("x-dimension"), new Integer(0));
		htExtra.put(new String("y-dimension"), new Integer(0));
		htExtra.put(new String("other"), new Integer(0));
		

		//furniture domain specific
		htMissing.put(new String("size"), new Integer(0));
		htExtra.put(new String("size"), new Integer(0));

		//people domain specific
		htMissing.put(new String("hasGlasses"), new Integer(0));
		htMissing.put(new String("hasBeard"), new Integer(0));
		htMissing.put(new String("hairColour"), new Integer(0));
		htMissing.put(new String("hasHair"), new Integer(0));
		htMissing.put(new String("age"), new Integer(0));
		htMissing.put(new String("hasSuit"), new Integer(0));
		htMissing.put(new String("hasShirt"), new Integer(0));
		htMissing.put(new String("hasTie"), new Integer(0));
		htExtra.put(new String("hasGlasses"), new Integer(0));
		htExtra.put(new String("hasBeard"), new Integer(0));
		htExtra.put(new String("hairColour"), new Integer(0));
		htExtra.put(new String("hasHair"), new Integer(0));
		htExtra.put(new String("age"), new Integer(0));
		htExtra.put(new String("hasSuit"), new Integer(0));
		htExtra.put(new String("hasShirt"), new Integer(0));
		htExtra.put(new String("hasTie"), new Integer(0));
		
		Integer count;
		
		Enumeration<String> e;
		String sK;
		greInterface tmpGRE;
		
		String missing = "";
		String extra = "";
		boolean m = false;
		boolean ex = false;
		
		iterT = vTrials.iterator();
		iterD = vSysAttSet.iterator();
		while(iterT.hasNext() && iterD.hasNext()) {
			tmpT = iterT.next();
			tmpGRE = iterD.next();
			if(tmpT.getID().equals(tmpGRE.getID())) {
				m = false;
				ex = false;
				missing = "Missing attributes: ";
				extra = "Extra attributes: ";
				htDes = (tmpT.getDescription()).getHashtableDescription();
				
				htGRE = tmpGRE.getDescripton();
				
				//output the attributes in the corpus description that the system did not include
				e = htDes.keys();
				while(e.hasMoreElements()) {
					sK = (String)e.nextElement();
					if(!htGRE.containsKey(sK)) {
						if(htMissing.containsKey(sK)) {
							count = htMissing.get(sK);
							count++;
							htMissing.put(sK, count);
						} 
						missing = missing + ", " + sK;
						m = true;
					}
				}
				//output the attributes in the system description that the system used and shouldn't have
				e = htGRE.keys();
				while(e.hasMoreElements()) {
					sK = (String)e.nextElement();
					if(!htDes.containsKey(sK)) {
						if(htExtra.containsKey(sK)) {
							count = htExtra.get(sK);
							count = new Integer(count.intValue()+1);
							htExtra.put(sK, count);
						}

						extra = extra + ", " + sK;
						ex = true;
					}
				}
				
				if((m) || (ex)) {
					System.out.println("Trial : " + tmpT.getID());
					//System.out.println("Corpus description:");
					//System.out.println(tmpT.getDescription().getStringDescription());
					//System.out.println("GRE description:");
					//System.out.println(tmpGRE.xmlDescription());
					System.out.println(missing);
					System.out.println(extra);
					System.out.println("**********");
				}				
			} else {
				System.err.println("corpusSystemDifference: iterators not aligned!");
			}
		}
		System.out.println("Missing: ");
		e = htMissing.keys();
		while(e.hasMoreElements()) {
			sK = e.nextElement();
			System.out.println(sK + ": " + htMissing.get(sK).toString());
		}
		System.out.println("Extra: ");
		e = htExtra.keys();
		while(e.hasMoreElements()) {
			sK = e.nextElement();
			System.out.println(sK + ": " + htExtra.get(sK).toString());
		}
	}

	
	public void outputNondistinguishingTrials() {
		Trial tmp;
		Iterator<Trial> i = vTrials.iterator();
		while(i.hasNext()) {
			tmp = i.next();
			if(!tmp.IsDistinguishing()) {
				System.out.println("Trial " + tmp.getID() + ": description is not distinguishing!");
			}
		}
	}

	
	/*
	 * Arg1 = boolean value that controls whether the frequency data is output to the stdout
	 * The function computes the number of times each attribute was used in a description in the corpus
	 * and store each attribute as values in the hmAttFreq HashMap<String, Integer> data structure, 
	 * keys = Attributes, values = occurrences.
	 * The function also sets the totalCount variable = the total number of attributes used in all the
	 * corpus descriptions
	 */
	public void computeAttFreq(boolean output) {
		hmAttFreq = new HashMap<String, Integer>();
		
		Hashtable<String, String> htTargetAttributes;
		Enumeration<String> e;
		
		String k;
		Integer count;
		Iterator<Trial> j = vTrials.iterator();
		Trial t;
		while(j.hasNext()) {
			t = (Trial)j.next();
							
			htTargetAttributes = t.getDescription().getHashtableDescription();
			//get the counts for each attribute used in a description
			e = htTargetAttributes.keys();
			while(e.hasMoreElements()) {
				totalCount++; //keep a count of the total number of attributes used
					          //in all the descriptions (used to compute probabilities
				k = e.nextElement();
				if(hmAttFreq.containsKey(k)) {
					count = (Integer)hmAttFreq.get(k);
					count++;
					hmAttFreq.put(k,count);
				} else {
					hmAttFreq.put(k, new Integer(1));
				}		
			}	
		}
		
		if(output) {
			Set<String> ks = hmAttFreq.keySet();
			Iterator<String> iterKey = ks.iterator();
			String sKey;
			while(iterKey.hasNext()) {
				sKey = iterKey.next();
				System.out.println("Attribute: " + sKey + " Occurrences: " + hmAttFreq.get(sKey));
			}
		}

		
		
		//sort the attributes based on the frequencies
		/*int size = htFrequencies.size();
		Enumeration f = htFrequencies.keys();
		while(f.hasMoreElements()) {
			k = (String)f.nextElement();
			v = (Integer)htFrequencies.get(k);
			while(tmAttFreq.containsKey(v)) {
				System.err.println("Error in computeAttributeFrequency: duplicate frequencies!");
				System.err.println("Decrementing frequency of attribute " + k);
				v--;
			}
			tmAttFreq.put(v,k);
		}
		
		if(output) {
		Set ks = tmAttFreq.keySet();
		Iterator fi = ks.iterator();
		Integer freq;
		while(fi.hasNext()) {
			freq = (Integer)fi.next();
			System.out.println("freq: " + freq + " att: " + (String)tmAttFreq.get(freq));
		}*/
		}
		
		
		public void outputDimensionalUsageAnalysis() {
			TreeMap<String, Integer> tmNeither = new TreeMap<String, Integer>();
			TreeMap<String, Integer> tmXOnly = new TreeMap<String, Integer>();
			TreeMap<String, Integer> tmYOnly = new TreeMap<String, Integer>();
			TreeMap<String, Integer> tmXandY = new TreeMap<String, Integer>();
					
			Trial tmp;
			
			AttributeSet d;
			Entity target;
			String hash;
			String cond;
			Integer tmpInt;
			Hashtable<String, String> ht;
			
			Iterator<Trial> i = vTrials.iterator();
			while(i.hasNext()) {
				tmp = i.next();
				//System.out.println("Trial id: " + tmp.getID());
				d = tmp.getDescription();
				target = (tmp.getDomain()).getTarget();
				ht = target.getAttributes();
			
				hash = "row =" + ht.get("y-dimension")  + " column = " + ht.get("x-dimension") + " condition = " + tmp.getCondition(); 
				if (!d.containsOther()) {
					if (d.containsXDimension() && d.containsYDimension()) {
						if (tmXandY.containsKey(hash)) {
							tmpInt = tmXandY.get(hash);
							tmpInt++;
							tmXandY.put(hash, tmpInt);
						} else {
							tmXandY.put(hash, new Integer(1));
						}
					} else if (d.containsXDimension()) {
						if (tmXOnly.containsKey(hash)) {
							tmpInt = tmXOnly.get(hash);
							tmpInt++;
							tmXOnly.put(hash, tmpInt);
						} else {
							tmXOnly.put(hash, new Integer(1));
						}
					} else if (d.containsYDimension()) {
						if (tmYOnly.containsKey(hash)) {
							tmpInt = tmYOnly.get(hash);
							tmpInt++;
							tmYOnly.put(hash, tmpInt);
						} else {
							tmYOnly.put(hash, new Integer(1));
						}
					} else {
						if (tmNeither.containsKey(hash)) {
							tmpInt = tmNeither.get(hash);
							tmpInt++;
							tmNeither.put(hash, tmpInt);
						} else {
							tmNeither.put(hash, new Integer(1));
						}
					}
				}
			}
			
			String k;
			Set<String> s = tmNeither.keySet();
			Iterator<String> iter = s.iterator();
			System.out.println("******************************");
			System.out.println("*           Neither          *");
			System.out.println("******************************");
			while(iter.hasNext()) {
				k = iter.next();
				System.out.println("pos: " + k + " count: " + tmNeither.get(k));
			}
			s = tmYOnly.keySet();
			iter = s.iterator();
			System.out.println("******************************");
			System.out.println("*           Y Only          *");
			System.out.println("******************************");
			while(iter.hasNext()) {
				k = iter.next();
				System.out.println("pos: " + k + " count: " + tmYOnly.get(k));
			}
			s = tmXOnly.keySet();
			iter = s.iterator();
			System.out.println("******************************");
			System.out.println("*           X Only          *");
			System.out.println("******************************");
			while(iter.hasNext()) {
				k = iter.next();
				System.out.println("pos: " + k + " count: " + tmXOnly.get(k));
			}
			s = tmXandY.keySet();
			iter = s.iterator();
			System.out.println("******************************");
			System.out.println("*          X and Y           *");
			System.out.println("******************************");
			while(iter.hasNext()) {
				k = iter.next();
				System.out.println("pos: " + k + " count: " + tmXandY.get(k));
			}		
		}

		
		/*public void printWordFrequencies(){
			
			DescriptionWordCounts wordCounts = new DescriptionWordCounts();
			
			Iterator<Trial> j = vTrials.iterator();
			Trial t;
			while(j.hasNext()) {
				t = j.next();
				
				String wordString = t.getWordString();
				
				AttributeSet description = t.getDescription();
				
				Hashtable<String, String> attributeValuePairs = description.getHashtableDescription();
				
				String k,v;
				
				Enumeration<String> e = attributeValuePairs.keys();
				while(e.hasMoreElements()) {
					k = e.nextElement();
					v = attributeValuePairs.get(k);
					
					wordCounts.addDescriptionText(k, v, wordString);
				}
			}
			
			System.out.println(wordCounts.toString());
		}
		*/

		
		
} //end class
